//// Copyright 2008 David Mitchell
//// Released under the MIT License

//using System;
//using System.Collections.Generic;
//using System.Globalization;
//using System.Runtime.InteropServices;

//namespace NSDuctTape
//{
//  internal class ObjectiveCClass
//  {
//    public ObjectiveCClass(string className, Type wrappedType, ObjectiveCClass metaClass, ObjectiveCClass baseClass, ClassKind classKind)
//    {
//      if (className == null)
//        throw new ArgumentNullException("className");
//      if (className.Length == 0)
//        throw new ArgumentException("className cannot be empty.", "className");
//      if (metaClass != null && !metaClass.IsRegistered)
//        throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "MetaClass '{0}' must be registered before being used.", metaClass.Name));
//      if (baseClass != null && !baseClass.IsRegistered)
//        throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "BaseClass '{0}' must be registered before being used.", baseClass.Name));
//      if (classKind != ClassKind.Class && classKind != ClassKind.MetaClass)
//        throw new ArgumentException("ClassKind must be either Class or MetaClass.");

//      _info.version = 1;
//      _info.className = Marshal.StringToHGlobalAnsi(className);
//      _info.metaClass = metaClass != null ? metaClass._nativeInfo : IntPtr.Zero;
//      _info.baseClass = baseClass != null ? baseClass._nativeInfo : IntPtr.Zero;
//      _info.instanceSize = baseClass != null ? baseClass._info.instanceSize : 0;
//      _info.info = classKind == ClassKind.Class ? ClassFlags.Class : ClassFlags.MetaClass;

//      _nativeInfo = Marshal.AllocHGlobal(Marshal.SizeOf(_info));
//      Marshal.StructureToPtr(_info, _nativeInfo, false);

//      _wrappedType = wrappedType;
//    }

//    public static ObjectiveCClass GetClass(string className)
//    {
//      return GetClass(ObjectiveCMethods.GetClass(className));
//    }

//    public static ObjectiveCClass GetClass(IntPtr nativeInfo)
//    {
//      if (nativeInfo == IntPtr.Zero)
//        return null;
//      if (s_registeredClasses.ContainsKey(nativeInfo))
//        return s_registeredClasses[nativeInfo];
//      return new ObjectiveCClass(nativeInfo);
//    }

//    public static ObjectiveCClass GetClass(IntPtr nativeInfo, Type wrappedType)
//    {
//      if (nativeInfo == IntPtr.Zero)
//        return null;
//      if (s_registeredClasses.ContainsKey(nativeInfo))
//        return s_registeredClasses[nativeInfo];
//      ObjectiveCClass result = new ObjectiveCClass(nativeInfo, wrappedType);
//      s_registeredClasses[nativeInfo] = result;
//      return result;
//    }

//    public static ObjectiveCClass GetClassForInstance(IntPtr nativeInstance)
//    {
//      return GetClass(ObjectiveCMethods.SendMessage(nativeInstance, c_selectorClass));
//    }

//    public ObjectiveCClass MetaClass
//    {
//      get { return _info.metaClass == IntPtr.Zero ? null : new ObjectiveCClass(_info.metaClass); }
//    }

//    public ObjectiveCClass BaseClass
//    {
//      get { return _info.baseClass == IntPtr.Zero ? null : new ObjectiveCClass(_info.baseClass); }
//    }

//    public string Name
//    {
//      get { return Marshal.PtrToStringAnsi(_info.className); }
//    }

//    public Type WrappedType { get { return _wrappedType; } }

//    public bool IsRegistered { get { return (_info.info & ClassFlags.Initialized) == ClassFlags.Initialized || _isRegistered; } }

//    public ClassKind ClassKind { get { return (_info.info & ClassFlags.Class) == ClassFlags.Class ? ClassKind.Class : ClassKind.MetaClass; } }

//    public int InstanceSize { get { return _info.instanceSize; } }

//    public void Register()
//    {
//      if (IsRegistered)
//        throw new InvalidOperationException("Classes cannot be registered twice.");

//      ObjectiveCMethods.AddClass(_nativeInfo);

//      _info = MarshalUtility.PtrToStructure<ObjectiveCClassInfo>(_nativeInfo);
//      _isRegistered = true;
//      s_registeredClasses[_nativeInfo] = this;
//    }

//    //public void AddMethods(ObjectiveCMethodList methods)
//    //{
//    //  if (!IsRegistered)
//    //    throw new InvalidOperationException("Class must be registered before adding methods.");

//    //  ObjectiveCMethods.AddMethodsToClass(_nativeInfo, methods.ToIntPtr());
//    //}

//    public IntPtr Instantiate()
//    {
//      if (!IsRegistered)
//        throw new InvalidOperationException("Class must be registered prior to instantiation.");

//      return ObjectiveCMethods.CreateInstance(_nativeInfo, 0);
//    }

//    public IntPtr ToIntPtr()
//    {
//      return _nativeInfo;
//    }

//    private ObjectiveCClass(IntPtr nativeInfo)
//    {
//      _nativeInfo = nativeInfo;
//      _info = MarshalUtility.PtrToStructure<ObjectiveCClassInfo>(nativeInfo);
//      _isRegistered = true;
//    }

//    private ObjectiveCClass(IntPtr nativeInfo, Type wrappedType)
//    {
//      _nativeInfo = nativeInfo;
//      _info = MarshalUtility.PtrToStructure<ObjectiveCClassInfo>(nativeInfo);
//      _isRegistered = true;
//      _wrappedType = wrappedType;
//    }

//    readonly IntPtr _nativeInfo;
//    ObjectiveCClassInfo _info;
//    bool _isRegistered;
//    readonly Type _wrappedType;
//    static readonly Dictionary<IntPtr, ObjectiveCClass> s_registeredClasses = new Dictionary<IntPtr, ObjectiveCClass>();

//    static readonly IntPtr c_selectorClass = ObjectiveCMethods.SelectorFromString("class");

//    [StructLayout(LayoutKind.Sequential)]
//    private struct ObjectiveCClassInfo
//    {
//      public IntPtr metaClass;
//      public IntPtr baseClass;
//      public IntPtr className;
//      public int version;
//      public ClassFlags info;
//      public int instanceSize;
//      public IntPtr instanceVariables;
//      public IntPtr methodLists;
//      public IntPtr cache;
//      public IntPtr protocols;
//    }
		
//    [StructLayout(LayoutKind.Sequential)]
//    private struct InstanceVariableList
//    {
//      public int Count;
//    }
		
//    [StructLayout(LayoutKind.Sequential)]
//    private struct InstanceVariable
//    {
//      public IntPtr Name;
//      public IntPtr Type;
//      public int Offset;
//    }
//  }
//}
